package clientGUI;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import javax.swing.*;

import clientApp.Plan;
import clientApp.VirtualAdvisor;
import clientGUI.studentGUI.EditSemestersInPlan;
import clientGUI.studentGUI.GUI_Function_Library;

public class SelectCoursesGUI_Catalog {
	private JFrame frame;
	private HashSet<String> selectedCourses;
	private ArrayList<JCheckBox> coursesAvailable;
	private boolean ready;
	private Plan plan;
	private String semester;
	private PassBackToable parentCaller;
	private VirtualAdvisor myVA;
	private String degreeSelected;
	private String categorySelected;
	private JComboBox degreeDropdown;
	private JComboBox categoryDropdown;
	private DefaultComboBoxModel degreeModel;
	private DefaultComboBoxModel categoryModel;
	private String cmd;
	private boolean limit1course;
	
	//TODO: make sure they can't add courses to semester if the credit limit would be passed
	
	public SelectCoursesGUI_Catalog(PassBackToable parentCaller, String cmd, boolean limit1course, VirtualAdvisor VA) throws InterruptedException
	{
		this(parentCaller, cmd, limit1course, new Plan(""), VA);
	}
	public SelectCoursesGUI_Catalog(PassBackToable parentCaller, String cmd, boolean limit1course, Plan plan, VirtualAdvisor VA) throws InterruptedException
	{
		selectedCourses = new HashSet<String>();
		coursesAvailable = new ArrayList<JCheckBox>();
		ready = false;
		this.plan = plan;
		this.parentCaller = parentCaller;
		myVA = VA;
		this.limit1course = limit1course;
		this.cmd = cmd;
		
		degreeModel = new DefaultComboBoxModel();
		categoryModel = new DefaultComboBoxModel();
		degreeDropdown = new JComboBox(degreeModel);
		categoryDropdown = new JComboBox(categoryModel);
		
		String instruction = (limit1course? "Select 1 course" : "Select courses");
		
		JPanel addCoursePane = createPaneADDCOURSES(instruction);
		frame = GUI_Function_Library.displayPane("Select Courses", addCoursePane, false);
		frame.resize(500, 700);
		
	}

	/*
	 * CONNECT TO DATABASE
	 * COURSE CHECKBOXES SUCK
	 */
	private JPanel createPaneADDCOURSES(String instruction)
	{
		// instructions
		JLabel userInstruction = new JLabel(instruction);

		// EAST
		JPanel selectedPane = new JPanel(new GridLayout(2,1));
		selectedPane.setBorder(BorderFactory.createTitledBorder("Selected Courses"));
		//
		final JPanel selectedCoursesPane = new JPanel();
		selectedCoursesPane.setLayout(new BoxLayout(selectedCoursesPane, BoxLayout.PAGE_AXIS));
		//
		JScrollPane scrollSelectedPane = new JScrollPane(selectedCoursesPane);
		scrollSelectedPane.setPreferredSize(new Dimension(200, 200));
		//
		JButton submitButton = new JButton("Submit");

		// add course to.. semester
		/* Rotem changed this to fix crash caused by eligibleSemesters = null. */
		String[] eligibleSemesters = EditSemestersInPlan.getSemesterSeasonsAndYears(plan);
		if (eligibleSemesters == null) {
			//TODO: once add/remove semesters are implemented, this can be handled better
			eligibleSemesters = new String[]{""};
		}
		/* End code edited by Rotem */

		final JComboBox selectSemesterDropdown = new JComboBox(eligibleSemesters);
		//
		
		
		submitButton.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				if(limit1course && selectedCourses.size() != 1)
					JOptionPane.showMessageDialog(null, "Please select a single course.");
				else {
					ready = true;
					semester = (String)selectSemesterDropdown.getSelectedItem();
					frame.setVisible(false);
					
					String courseString = "";
					for(String data : selectedCourses)
					{
						if(!data.isEmpty())
							courseString += "," + data;
					}
					
		
					try {
						String message =  semester + "," + courseString;
						message = message.replaceAll(",,", ",");
						parentCaller.passBack(cmd, message);
					} catch (Exception e1) {
						GUI_Function_Library.exceptionHandler("AddCoursesGUI:submitButtonListener", e1);
					}
				}
			}
		});

		//
		JPanel selectedCoursesActionPane = new JPanel();
		selectedCoursesActionPane.add(selectSemesterDropdown);
		selectedCoursesActionPane.add(submitButton);
		//
		selectedPane.add(scrollSelectedPane);
		selectedPane.add(selectedCoursesActionPane);
		
		// WEST
		// add class pane - courses list
		degreeSelected		= myVA.getDegreeNames()[0];
		categorySelected	= myVA.getCategories(degreeSelected)[0];
		String[] allCourses = myVA.isAdmin() ? myVA.getCourseSet(degreeSelected, categorySelected) :
				myVA.getAvailableCourses(degreeSelected, categorySelected, plan.getPlanName());
		//
		JScrollPane courseListScrollPane = new JScrollPane();
		final JPanel courseListPane = new JPanel();
		courseListPane.setLayout(new BoxLayout(courseListPane, BoxLayout.PAGE_AXIS));
		courseListScrollPane.add(courseListPane);

		for(final String courseName: allCourses)
		{
			final JCheckBox currentCourseCheckBox = new JCheckBox(courseName);
			courseListPane.add(currentCourseCheckBox);
			coursesAvailable.add(currentCourseCheckBox);
			setAvailableActionListener(selectedCoursesPane, courseListPane, currentCourseCheckBox);
		}
				
		// add class pane - the whole thing
		JPanel addClassPane = new JPanel();
		addClassPane.setBorder(BorderFactory.createTitledBorder("Add Class"));
		addClassPane.setLayout(new BoxLayout(addClassPane, BoxLayout.PAGE_AXIS));
		//
		JLabel degreeLabel	= new JLabel("Degree Program");
		String[] degreeOptions	= myVA.getDegreeNames();
		resetComboBoxModel(degreeModel, degreeOptions);
		degreeDropdown.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				degreeSelected = (String)degreeDropdown.getSelectedItem();
				String[] categories = myVA.getCategories(degreeSelected);
				categorySelected = categories[0];
				
				//Category drop down action listener will get called and populate class list
				resetComboBoxModel(categoryModel, categories);
			}
		});
		//
		JLabel categoryLabel = new JLabel("Category");
		String[] categories = myVA.getCategories(degreeSelected);
		resetComboBoxModel(categoryModel, categories);
		categoryDropdown.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				if (categoryModel.getSelectedItem() != null) {										
					categorySelected = (String)categoryDropdown.getSelectedItem();
					String[] allCourses = myVA.getAvailableCourses(degreeSelected, categorySelected, plan.getPlanName());

					courseListPane.removeAll();
	
					for(final String courseName: allCourses)
					{
						if (!selectedCourses.contains(courseName)) {
							final JCheckBox currentCourseCheckBox = new JCheckBox(courseName);
							courseListPane.add(currentCourseCheckBox);
							coursesAvailable.add(currentCourseCheckBox);
							setAvailableActionListener(selectedCoursesPane, courseListPane, currentCourseCheckBox);
						}
					}
					frame.validate();
				}
			}
		});
		//
		JLabel coursesLabel = new JLabel("Courses");
		// + courseListPane

		//
		addClassPane.add(degreeLabel);
		addClassPane.add(degreeDropdown);
		addClassPane.add(categoryLabel);
		addClassPane.add(categoryDropdown);
		addClassPane.add(coursesLabel);
		addClassPane.add(courseListPane);

		BorderLayout myBL = new BorderLayout();
		myBL.setHgap(50);
		JPanel transcriptPane = new JPanel(myBL);
		transcriptPane.add(userInstruction,		BorderLayout.NORTH);
		transcriptPane.add(selectedPane,		BorderLayout.CENTER);
		transcriptPane.add(addClassPane,		BorderLayout.WEST);
		//selectedPane.resize(selectedPane.getWidth()+100, selectedPane.getHeight());
		return transcriptPane;
	}
	
	private void resetComboBoxModel(DefaultComboBoxModel model, String[] newOptions) {
		model.removeAllElements();
		coursesAvailable.clear();
		
		for (int i = 0; i < newOptions.length; i++) {
			model.addElement(newOptions[i]);
		}
	}
	
	private void moveCheckBox(final JPanel source, final JPanel destination, final JCheckBox item) {
		//remove from source
		source.remove(item);
		source.updateUI();
				
		//add to destination (in alphanumeric order)						
		Component[] items = destination.getComponents();
		for (int i = 0; i < items.length; i++) {
			Component object = items[i];
			String checkbox = item.getClass().toString();
			if (object.getClass().toString().equals(checkbox)) {
				String objectText = ((JCheckBox)object).getText();
				if (objectText.compareTo(item.getText()) > 0) {
					destination.add(item, i);
					frame.validate();
					return;
				}
			}
		}
		
		//destination is empty
		destination.add(item);
		frame.validate();
	}
	
	private void setSelectedActionListener(final JPanel selectedPanel, final JPanel availablePanel, final JCheckBox course) {
		course.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				selectedCourses.remove(course.getText());
				course.removeActionListener(this);
				setAvailableActionListener(selectedPanel, availablePanel, course);
				
				//If removed course belongs in the current list of available courses, refresh the list
				String[] coursesInSection = myVA.getAvailableCourses(degreeSelected, categorySelected, plan.getPlanName());
				if ((Arrays.binarySearch(coursesInSection, course.getText()) >= 0) &&
					(!coursesAvailable.contains(course.getText()))) {
					coursesAvailable.add(course);
					moveCheckBox(selectedPanel, availablePanel, course);
				} else {
					selectedPanel.remove(course);
					selectedPanel.updateUI();
				}
			}
		});
	}
	
	private void setAvailableActionListener(final JPanel selectedPanel, final JPanel availablePanel, final JCheckBox course) {
		course.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				//Check to see if the equivalent (honors/non honors) course has already been selected
				String checker = course.getText().indexOf("H") == -1 ? course.getText() + "H" :
										course.getText().substring(0, course.getText().length() - 1);
				if ((selectedCourses.contains(checker))) {
					int addConfirm = JOptionPane.showConfirmDialog(null, checker + " is already selected. Would you like to select " + course.getText() + " instead?");	
					if((addConfirm == JOptionPane.NO_OPTION) || (addConfirm == JOptionPane.CANCEL_OPTION))	{
						//Nevermind, don't add the course
						course.setSelected(false);
						return;
					} else {
						//Find other course
						JCheckBox otherCourse = null;
						Component[] selected = selectedPanel.getComponents();
						for (Component object : selected) {
							String checkbox = course.getClass().toString();
							if (object.getClass().toString().equals(checkbox)) {
								String objectText = ((JCheckBox)object).getText();
								if (objectText.equals(checker)) {
									otherCourse = (JCheckBox)object;
									otherCourse.setSelected(false);
									break;
								}
							}
						}
						
						//Remove other course
						selectedCourses.remove(checker);
						ActionListener[] listeners = otherCourse.getActionListeners();
						otherCourse.removeActionListener(listeners[0]);
						setAvailableActionListener(selectedPanel, availablePanel, otherCourse);
						
						//If removed course belongs in the current list of available courses, refresh the list
						String[] coursesInSection = myVA.getAvailableCourses(degreeSelected, categorySelected, plan.getPlanName());
						if ((Arrays.binarySearch(coursesInSection, otherCourse.getText()) >= 0) &&
							(!coursesAvailable.contains(otherCourse.getText()))) {
							coursesAvailable.add(otherCourse);
							moveCheckBox(selectedPanel, availablePanel, otherCourse);
						} else {
							selectedPanel.remove(otherCourse);
							selectedPanel.updateUI();
						}
					}
				}
				
				coursesAvailable.remove(course);
				selectedCourses.add(course.getText());
				moveCheckBox(availablePanel, selectedPanel, course);
				course.removeActionListener(this);
				setSelectedActionListener(selectedPanel, availablePanel, course);
			}
		});
	}
}
